package com.pay.dubbo.wx.impl;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.pay.beans.ReturnContent;
import com.pay.common.util.DigestUtil;
import com.pay.common.util.PropertyUtil;
import com.pay.constants.ExpriseTimeConstants;
import com.pay.constants.MarketplanConstant;
import com.pay.constants.RedisKeyConstants;
import com.pay.constants.RetConstants;
import com.pay.dubbo.wx.EnterPrisePaymentServiceFacade;
import com.pay.dubbo.wx.WxServiceFacade;
import com.pay.entity.wx.WxPayBill;
import com.pay.entity.wx.WxPayDetail;
import com.pay.entity.wx.WxPayTemplate;
import com.pay.enums.SuccessFail;
import com.pay.enums.WxPayStatus;
import com.pay.service.AccessTokenService;
import com.pay.service.WxPayBillService;
import com.pay.service.WxPayDetailService;
import com.pay.service.WxPayTemplateService;
import com.pay.util.HttpClientUtil;
import com.pay.util.RedisUtil;
import com.pay.util.RequestUtil;
import com.pay.util.UUIDHexGenerator;
import com.pay.wx.dubbo.EnterPriseOuterServiceFacade;

/**
 * @Description: 企业付款服务
 * @see: EnterPrisePaymentServiceFacadeImpl 此处填写需要参考的类
 * @version 2016年12月27日 下午4:14:34
 * @author shulin.feng
 * @param <T>
 */
@Service("enterPrisePaymentServiceFacade")
public class EnterPrisePaymentServiceFacadeImpl<T> implements EnterPrisePaymentServiceFacade {
	private Logger logger = LoggerFactory.getLogger(EnterPrisePaymentServiceFacadeImpl.class);

	@Resource
	private WxServiceFacade wxServiceFacade;

	@Resource
	private WxPayBillService wxPayBillService;

	@Resource
	private AccessTokenService accessTokenService;

	@Resource
	private WxPayTemplateService wxPayTemplateService;

	@Resource
	private WxPayDetailService wxPayDetailService;

	@Resource
	private EnterPriseOuterServiceFacade enterPriseOuterServiceFacade;

	private static String outAppSecret;// 项目路径
	private static String actId;
	static {
		PropertyUtil propertyUtil = PropertyUtil.getInstance("wxweb");
		outAppSecret =  propertyUtil.getProperty("com.pay.wx.outAppSecret");
		actId =  propertyUtil.getProperty("pay.redpacket.actId");
	}
	
	@Override
	public String payment(String partnerTradeNo) {
		String code = RetConstants.SUCCESS;// 返回编号
		String msg = "";// 返回消息
		try {
			// 验证商户订单号是否存在
			WxPayBill wxPayBill = wxPayBillService.findPayBillByPartnerTradeNo(partnerTradeNo);
			logger.info("EnterPrisePaymentServiceFacadeImpl/payment/wxPayBill:{}", JSON.toJSONString(wxPayBill));
			if (wxPayBill != null) {
				// 放入redis，防止重复领取
				int partnerStatus = RedisUtil.setnx(RedisKeyConstants.ENTERPRISE_PARTNERTRAD_NO + partnerTradeNo, partnerTradeNo,
						ExpriseTimeConstants.expriseTime300);
				if (0==partnerStatus) {
					logger.info("EnterPrisePaymentServiceFacadeImpl企业付款失败 redisNxError："+partnerTradeNo);
					return JSON.toJSONString(new ReturnContent<>(RetConstants.ERROR, "您已经领取过了！"));
				}
				
				// return_code 和result_code都为SUCCESS标示已经领取过
				if ("00".equals(wxPayBill.getReturnCode())
						&& "00".equals(wxPayBill.getResultCode())) {
					logger.info("EnterPrisePaymentServiceFacadeImpl企业付款失败 statusError ："+partnerTradeNo);
					return JSON.toJSONString(new ReturnContent<>(RetConstants.ERROR, "您已经领取过了！"));
				}
				
				// 验证当前订单是否存在红包模板信息
				WxPayTemplate wxPayTemplate = wxPayTemplateService.findTemplateByOutTradeNo(wxPayBill.getOuterAppid(),
						wxPayBill.getOuterTradeNo());
				if (wxPayTemplate == null) {
					logger.info("EnterPrisePaymentServiceFacadeImpl企业付款失败wxPayTemplateError ："+partnerTradeNo);
					return JSON.toJSONString(new ReturnContent<>(RetConstants.ERROR,RetConstants.ERROR_MSG));
				}
				/**
				   * 第三方调用付款服务，比如：I刷红包
				   * 需要在微信建立account表的记录。
				   * @Description 企业付款
				   * @author yingjie.guo
				   * @param customerNo  商户编号
				   * @param actId      活动编号,需要在微信活动提前定义
				   * @param lsOpenId     对应发红包公众号的openid
				   * @param amount    金额
				   * @param ip      领红包商户IP
				   * @param desc      付款描述（模版中的入账详情）
				   * @param outerTradeNo  外部订单号
				   * @return code（00：成功；98：支付失败；99系统异常；）msg（描述）tradeNo（成功的支付订单号）
				   * @see 需要参考的类或方法
				   */
				Map<String, String> map = enterPriseOuterServiceFacade.paymentToCustomer(wxPayTemplate.getUserNo(), actId
																			, wxPayBill.getOpenid(),wxPayBill.getAmount().setScale(2).toString(),
																					wxPayBill.getIp(), wxPayBill.getDesc(), wxPayBill.getPartnerTradeNo());
//测试				Map<String, String> map = new HashMap<String,String>();				
//				map.put("code", "00");map.put("msg", "成功");map.put("tradeNo", ""+System.currentTimeMillis());
				logger.info("EnterPrisePaymentServiceFacadeImpl/payment/map:{}", JSON.toJSONString(map));
				// 通信标识
				String return_code = map.get("code");
				// 业务结果
				String result_code = map.get("code");
				if ("00".equals(return_code)) {
					wxPayBill.setReturnCode(return_code);
					if ("00".equals(result_code)) {
						wxPayBill.setResultCode(result_code);
						wxPayBill.setPaymentNo(map.get("tradeNo"));
						wxPayBill.setPaymentTime(new Date());
						msg = "领取成功";
						logger.info("EnterPrisePaymentServiceFacadeImpl企业付款成功");

					} else {
						// 错误代码
						String err_code = map.get("code");
						// 错误代码描述
						String err_code_des = map.get("msg");
						// 系统异常，重试
						if ("SYSTEMERROR".equals(err_code)) {
							RedisUtil.del(RedisKeyConstants.ENTERPRISE_PARTNERTRAD_NO + partnerTradeNo);// 移除已经领取过key
							WxPayDetail wxPayDetail = new WxPayDetail(wxPayBill.getOuterAppid(),
									wxPayBill.getOuterTradeNo(), wxPayBill.getOuterOpenid(), wxPayTemplate.getUserNo(),
									WxPayStatus.FAIL.name(), err_code_des, null);
							wxPayDetailService.insert(wxPayDetail);
							return payment(partnerTradeNo);
						}
						code = RetConstants.ERROR;
						msg = err_code_des;
						wxPayBill.setErrCode(err_code);
						wxPayBill.setErrCodeDesc(err_code_des);
					}
				} else {
					// 返回信息
					String return_msg = map.get("msg");
					wxPayBill.setReturnMsg(return_msg);
					// 业务结果
					code = RetConstants.ERROR;
					if ("FAIL".equals(result_code)) {
						// 错误代码
						String err_code = map.get("code");
						// 错误代码描述
						String err_code_des = map.get("msg");
						msg = return_msg;
						wxPayBill.setErrCode(err_code);
						wxPayBill.setErrCodeDesc(err_code_des);
					}
				}
				logger.info("EnterPrisePaymentServiceFacadeImpl/payment/wxPayBill:{}", JSON.toJSONString(wxPayBill));
				wxPayBillService.update(wxPayBill);
				//修改 wxPayTemplate
				wxPayTemplate.setOpenid(wxPayTemplate.getOpenid());//联刷openId
				wxPayTemplate.setStatus(
						RetConstants.SUCCESS.equals(code) ? WxPayStatus.SUCCESS.name() : WxPayStatus.FAIL.name());
				// 更新红包模板状态
				wxPayTemplateService.update(wxPayTemplate);
				// 增加红包操作详情记录
				WxPayDetail wxPayDetail = new WxPayDetail(wxPayBill.getOuterAppid(), wxPayBill.getOuterTradeNo(),
						wxPayBill.getOuterOpenid(),wxPayTemplate.getUserNo(),
						RetConstants.SUCCESS.equals(code) ? WxPayStatus.SUCCESS.name() : WxPayStatus.FAIL.name(), msg,
						wxPayBill.getPaymentNo());
				wxPayDetailService.insert(wxPayDetail);
				// 红包结果异步通知
				pushNotifyInfo(wxPayBill.getPartnerTradeNo(), wxPayBill.getOuterTradeNo(), msg, code,
						wxPayBill.getRemark(), wxPayBill.getOuterAppid());
				// 失败及时清除缓存操作限制标识
				if (!"00".equals(return_code) || !"00".equals(result_code)) {
					RedisUtil.removeKeyValue(RedisKeyConstants.ENTERPRISE_PARTNERTRAD_NO + partnerTradeNo);
					// 将错误提示更改为好听的
					msg = "请稍候重试";
				}
				return JSON.toJSONString(new ReturnContent<>(code, msg,
						wxPayBill.getAmount().setScale(2, BigDecimal.ROUND_DOWN).toPlainString()));
			}
			return JSON.toJSONString(new ReturnContent<>(RetConstants.ERROR, "订单号不存在！"));
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("EnterPrisePaymentServiceFacadeImpl/payment/exceptioninfo:{}", e.getMessage());
			return JSON.toJSONString(new ReturnContent<>(RetConstants.ERROR, RetConstants.SYSTEM_ERROR_MSG));
		}
	}

	private String pushNotifyInfo(String partnerTradeNo, String outerTradeNo, String msg, String code, String notifyUrl,
			String outerAppId) {
		String result = null;
		try {
			Map<String, String> paramMap = new HashMap<String, String>();
			paramMap.put("partnerTradeNo", partnerTradeNo);
			paramMap.put("outerTradeNo", outerTradeNo);
			paramMap.put("handlerResult", msg);
			paramMap.put("handlerCode", code);
			String sortResult = RequestUtil.MapToStrSort(paramMap);
			logger.info("EnterPrisePaymentServiceFacadeImpl/pushNotifyInfo/sortResult:{}", sortResult);
			String sign = DigestUtil.md5(sortResult +outAppSecret);
			StringBuffer sb = new StringBuffer(notifyUrl)
									.append("?").append(sortResult)
									.append("&sign=").append(sign);
			logger.info("EnterPrisePaymentServiceFacadeImpl/pushNotifyInfo/notifyContent:{}", sb.toString());
			result = HttpClientUtil.httpRequest(sb.toString());
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}

	@SuppressWarnings("rawtypes")
	@Override
	public ReturnContent<?> createPayBill(Map<String, String> param) {
		logger.info("EnterPrisePaymentServiceFacadeImpl/createPayBill/param:{}", JSON.toJSON(param));
		String outerTradeNo = param.get("outerTradeNo");
		String outerAppId = param.get("outerAppId");
		String outerOpenId = param.get("outerOpenId");//友刷
		String openId = param.get("openId");//联刷
//		BigDecimal amount = new BigDecimal(param.get("amount"));
		String customerNo = param.get("customerNo");// 商户编号
		logger.info(JSON.toJSONString(param));
		try {
			// 查询活动信息
			// 创建订单前，判定外部商编下的订单号是否存在
			WxPayBill wxPayBill = wxPayBillService.findPayBillByOutTradeNo(outerAppId, outerTradeNo);
			if (wxPayBill == null) {
				// 防止重复创建订单
				int payBillCheck = RedisUtil.setnx(RedisKeyConstants.ENTERPRISE_PAY_BILL_NO + outerTradeNo + outerAppId,
						outerOpenId, ExpriseTimeConstants.expriseTime2);
				logger.info("EnterPrisePaymentServiceFacadeImpl/createPayBill/payBillCheck:{}", payBillCheck);
				if (1==payBillCheck) {
					// 查询红包模板信息
					WxPayTemplate wxPayTemplate = wxPayTemplateService.findTemplateByOutTradeNo(outerAppId,
							outerTradeNo);
					logger.info("EnterPrisePaymentServiceFacadeImpl/createPayBill/wxPayTemplate:{}", JSON.toJSON(wxPayTemplate));
					// 创建订单，放入redis，防止重复领取
					wxPayBill = new WxPayBill();
					UUIDHexGenerator uuidGenerator = UUIDHexGenerator.getInstance();
					wxPayBill.setOuterAppid(outerAppId);// 外部商户编号
					wxPayBill.setOuterOpenid(outerOpenId);// 外部商户openid 
					wxPayBill.setOuterTradeNo(outerTradeNo);// 外部商户订单号
					String today = new SimpleDateFormat("yyyyMMdd").format(new Date());
					String code = uuidGenerator.createCode(10);
//					String mchid = WeixinConstants.lzzymchid;// 商户号
					wxPayBill.setPartnerTradeNo(//mchid + 
							today + code);// 商户订单号
					wxPayBill.setOpenid(openId);// 接收款项用户openid--联刷
					wxPayBill.setNonceStr(uuidGenerator.generate());// 获取uuid作为随机字符串
					wxPayBill.setCheckName("NO_CHECK");// 校验用户姓名选项，默认为不校验
					wxPayBill.setAmount(wxPayTemplate.getAmount());// 打款金额
					wxPayBill.setDesc(param.get("desc"));// 企业付款描述
					wxPayBill.setIp(param.get("ip"));// 操作ip
					wxPayBill.setReturnCode(SuccessFail.FAIL.name());// 通信标示默认FAIL
					wxPayBill.setResultCode(SuccessFail.FAIL.name());// 下单业务结果默认FAIL
					wxPayBill.setRemark(param.get("notifyURL"));// 业务通知回调地址
					wxPayBillService.insert(wxPayBill);
					
					if (wxPayTemplate != null && !WxPayStatus.CREATESUCESS.name().equals(wxPayTemplate.getStatus())) {
						wxPayTemplate.setStatus(WxPayStatus.CREATESUCESS.name());
						wxPayTemplate.setOpenid(openId);
						// 更新红包模板操作状态
						wxPayTemplateService.update(wxPayTemplate);
					}
					WxPayDetail wxPayDetail = new WxPayDetail(outerAppId, outerTradeNo, outerOpenId, customerNo,
							WxPayStatus.CREATESUCESS.name(), "创建成功", null);
					// 增加红包操作详情记录
					wxPayDetailService.insert(wxPayDetail);
				} else {
					return new ReturnContent<Object>(RetConstants.ERROR, "操作频繁");
				}
			} else {
				logger.info("EnterPrisePaymentServiceFacadeImpl/createPayBill/wxPayBill:{}", JSON.toJSON(wxPayBill));
				if ("00".equals(wxPayBill.getResultCode())) {
					return new ReturnContent<String>(MarketplanConstant.PAY_SUCCESS, "该订单已打款成功", wxPayBill.getPartnerTradeNo()+":"+wxPayBill.getAmount().toString());
				}
			}
			return new ReturnContent<String>(RetConstants.SUCCESS, "创建成功", wxPayBill.getPartnerTradeNo()+":"+wxPayBill.getAmount().toString());
		} catch (Exception e) {
			logger.error("EnterPrisePaymentServiceFacadeImpl/createPayBill/exceptioninfo:{}", e.getMessage());
			return new ReturnContent<Object>(RetConstants.SYSTEM_ERROR, RetConstants.SYSTEM_ERROR_MSG);
		}
	}


	@Override
	public String sendPayTemplate(Map<String, String> param) {
		return wxPayTemplateService.sendPayTemplate(param);
	}

}
